package org.proteored.miapeapi.xml.pride.msi;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.cv.msi.MatchedPeaks;
import org.proteored.miapeapi.cv.msi.ProteinDescription;
import org.proteored.miapeapi.cv.msi.ValidationType;
import org.proteored.miapeapi.interfaces.msi.IdentifiedPeptide;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProtein;
import org.proteored.miapeapi.interfaces.msi.InputDataSet;
import org.proteored.miapeapi.interfaces.msi.ProteinScore;
import org.proteored.miapeapi.xml.pride.autogenerated.CvParamType;
import org.proteored.miapeapi.xml.pride.autogenerated.IdentificationType;
import org.proteored.miapeapi.xml.pride.autogenerated.ParamType;
import org.proteored.miapeapi.xml.pride.autogenerated.Peptide;
import org.proteored.miapeapi.xml.pride.autogenerated.UserParamType;
import org.proteored.miapeapi.xml.pride.util.PrideControlVocabularyXmlFactory;
import org.proteored.miapeapi.xml.util.MiapeXmlUtil;

public class IdentifedProteinImpl implements IdentifiedProtein {
	private static final int AdditionalInformationMaxLength = 8000;
	private final IdentificationType protein;
	private final ParamType additional;
	private final Integer identifier;
	private final Set<InputDataSet> inputDataSets;
	private final ControlVocabularyManager cvManager;

	public IdentifedProteinImpl(IdentificationType protein,
			Set<InputDataSet> inputDataSets, Integer identifier,
			ControlVocabularyManager cvManager) {
		this.protein = protein;
		this.identifier = identifier;
		this.inputDataSets = inputDataSets;
		additional = protein.getAdditional();
		this.cvManager = cvManager;
	}

	@Override
	public String getAccession() {
		StringBuilder sb = new StringBuilder();
		sb.append(protein.getAccession());
		if (protein.getAccessionVersion() != null) {
			sb.append(".");
			sb.append(protein.getAccessionVersion());
		}

		return sb.toString();
	}

	@Override
	public String getAdditionalInformation() {
		if (additional != null) {
			ParamType paramTypeToPrint = new ParamType();
			// I take all from additional except for the CV from Protein
			// description and from
			// validation status
			for (Object cvOrUserParam : additional.getCvParamOrUserParam()) {
				if (cvOrUserParam instanceof CvParamType) {
					CvParamType cvParam = (CvParamType) cvOrUserParam;
					boolean takeIt = true;
					if (cvParam.getAccession().equals(
							ProteinDescription.PRIDE_PROTEIN_DESCRIPTION_LINE
									.getTermAccession())
							|| cvParam.getAccession().equals(
									ProteinDescription.PSI_PROTEIN_DESCRIPTION
											.getTermAccession()))
						takeIt = false;
					if (cvParam.getAccession().equals(
							MatchedPeaks.NUMBER_OF_MATCHED_PEAKS
									.getTermAccession()))
						takeIt = false;
					if (cvParam.getAccession().equals(
							MatchedPeaks.NUMBER_OF_UNMATCHED_PEAKS
									.getTermAccession()))
						takeIt = false;

					if (takeIt)
						paramTypeToPrint.getCvParamOrUserParam().add(cvParam);

				} else if (cvOrUserParam instanceof UserParamType) {
					UserParamType userParam = (UserParamType) cvOrUserParam;
					if (!userParam
							.getName()
							.equals(PrideControlVocabularyXmlFactory.VALIDATION_STATUS_TEXT))
						paramTypeToPrint.getCvParamOrUserParam().add(userParam);
				}
			}
			final String writeParam = PrideControlVocabularyXmlFactory
					.writeParam(paramTypeToPrint);
			if (writeParam == null)
				return null;
			if (writeParam.length() > AdditionalInformationMaxLength)
				return writeParam.substring(0, AdditionalInformationMaxLength);
			return writeParam;
		}
		return null;
	}

	@Override
	public String getCoverage() {
		if (protein.getSequenceCoverage() != null) {
			return String.valueOf(protein.getSequenceCoverage());
		}
		return null;
	}

	@Override
	public String getDescription() {

		if (additional != null) {
			// Search for the CVs: PRIDE:0000063(protein description line)
			CvParamType cv = PrideControlVocabularyXmlFactory
					.getCvFromParamType(additional,
							ProteinDescription.PRIDE_PROTEIN_DESCRIPTION_LINE
									.getTermAccession());
			if (cv != null && cv.getValue() != null
					&& !"".equals(cv.getValue()))
				return cv.getValue();

			// Search for the CVs: "MS:1001088"(protein description)
			cv = PrideControlVocabularyXmlFactory.getCvFromParamType(
					additional, ProteinDescription.PSI_PROTEIN_DESCRIPTION
							.getTermAccession());
			if (cv != null && cv.getValue() != null
					&& !"".equals(cv.getValue()))
				return cv.getValue();

		}

		// if there was not any of the CV or userParam terms
		StringBuilder sb = new StringBuilder();

		if (getAccession() != null) {
			sb.append(getAccession());
		}
		if (protein.getDatabase() != null) {
			sb.append(" from " + protein.getDatabase());
		}
		if (protein.getDatabaseVersion() != null) {
			sb.append(" " + protein.getDatabaseVersion());
		}

		return sb.toString();
	}

	@Override
	public List<IdentifiedPeptide> getIdentifiedPeptides() {
		List<IdentifiedPeptide> peptides = new ArrayList<IdentifiedPeptide>();
		for (Peptide peptide : protein.getPeptideItem()) {
			peptides.add(new IdentifiedPeptideImpl(peptide, inputDataSets,
					MiapeXmlUtil.PeptideCounter.increaseCounter(), cvManager,
					this));

		}
		return peptides;
	}

	@Override
	public String getPeaksMatchedNumber() {
		if (additional != null) {
			final CvParamType cvParam = PrideControlVocabularyXmlFactory
					.getCvFromParamType(additional,
							MatchedPeaks.NUMBER_OF_MATCHED_PEAKS
									.getTermAccession());
			if (cvParam != null)
				return cvParam.getValue();
		}
		return null;
	}

	@Override
	public String getPeptideNumber() {
		if (protein.getPeptideItem() == null) {
			return null;
		}
		return String.valueOf(protein.getPeptideItem().size());
	}

	@Override
	public Set<ProteinScore> getScores() {
		final Double xmlScores = protein.getScore();
		if (xmlScores != null) {
			Set<ProteinScore> scores = new HashSet<ProteinScore>();
			scores.add(new ProteinScoreImpl(xmlScores));
			return scores;
		}
		return null;
	}

	@Override
	public String getUnmatchedSignals() {
		if (additional != null) {
			final CvParamType cvParam = PrideControlVocabularyXmlFactory
					.getCvFromParamType(additional,
							MatchedPeaks.NUMBER_OF_UNMATCHED_PEAKS
									.getTermAccession());
			if (cvParam != null)
				return cvParam.getValue();
		}
		return null;
	}

	@Override
	public Boolean getValidationStatus() {
		// search validation status in the additional
		if (additional != null) {
			for (Object cvOrUserParam : additional.getCvParamOrUserParam()) {
				if (cvOrUserParam instanceof UserParamType) {
					String[] cadenas = { PrideControlVocabularyXmlFactory.VALIDATION_STATUS_TEXT };
					if (PrideControlVocabularyXmlFactory
							.findTextInUserParamType(
									(UserParamType) cvOrUserParam,
									cadenas,
									org.proteored.miapeapi.interfaces.MatchMode.ANYWHERE
											.toString())) {
						try {
							return new Boolean(
									((UserParamType) cvOrUserParam).getValue());
						} catch (Exception ex) {
							// do nothing
						}
					}
				}
			}

		}
		return true;
	}

	@Override
	public String getValidationType() {
		if (additional != null) {
			final CvParamType cvParam = PrideControlVocabularyXmlFactory
					.getCvFromParamType(additional,
							ValidationType.getInstance(cvManager));
			if (cvParam != null)
				return cvParam.getName();
		}
		return null;
	}

	@Override
	public String getValidationValue() {
		if (additional != null) {
			final CvParamType cvParam = PrideControlVocabularyXmlFactory
					.getCvFromParamType(additional,
							ValidationType.getInstance(cvManager));
			if (cvParam != null)
				return cvParam.getValue();
		}
		return null;
	}

	@Override
	public String toString() {
		return "IdentifedProteinImpl [protein=" + protein + "]";
	}

	@Override
	public int getId() {
		if (identifier != null)
			return identifier;
		return -1;
	}

}
